package com.pinyoumei.service.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.pinyoumei.base.TaotaoResult;
import com.pinyoumei.constans.Constants;
import com.pinyoumei.mapper.TbPayMapper;
import com.pinyoumei.pay.service.PayCallBackService;
import com.pinyoumei.pojo.TbPay;
import com.pinyoumei.pojo.TbPayExample;
import com.pinyoumei.pojo.TbPayExample.Criteria;
import com.pinyoumei.service.feign.OrderServiceFegin;
import com.pinyoumei.utils.JsonUtils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@RestController
public class PayCallBackServiceImpl implements PayCallBackService {
	
	@Value("${alipay.public_key}")
	private String public_key;
	
	@Value("${alipay.charset}")
	private String charset;
	
	@Value("${alipay.sign_type}")
	private String sign_type;
	
	@Autowired
	private TbPayMapper payMapper;
	
	@Autowired
	private OrderServiceFegin orderServiceFeign;

	/**
	 * 同步回调
	 */
	@Override
	public String synCallBack(@RequestParam Map<String, String> params) {
		//1.接收支付宝传过来的参数,实际工作中,需要入库
		//params是点击支付后,支付宝通过浏览器重定向同步通知用户,展示支付结果的信息
		log.info("####同步回调开始####params:",JsonUtils.objectToJson(params));
		//2. 公钥验签
		try {
			boolean sign=AlipaySignature.rsaCheckV1(params, public_key, charset,sign_type);
			if(!sign){
				TaotaoResult result=TaotaoResult.build(901,"验签失败", "");
				return JsonUtils.objectToJson(result);
			}
			String outTradeNo = params.get("out_trade_no");// 商户订单号
			String tradeNo = params.get("trade_no");//支付宝交易号
			String totalAmount = params.get("total_amount");// 付款金额
			HashMap<String,Object> resultMap=new HashMap<String,Object>();
			resultMap.put("outTradeNo", outTradeNo);
			resultMap.put("tradeNo",tradeNo);
			resultMap.put("totalAmount",totalAmount);
			TaotaoResult result=TaotaoResult.build(200,"同步回调成功",resultMap);
			return JsonUtils.objectToJson(result);
		} catch (AlipayApiException e) {
			log.info("######PayCallBackServiceImpl##ERROR:#####", e);
			return JsonUtils.objectToJson(TaotaoResult.build(905,"验签错误",""));
		}finally{
			log.info("##########同步回调结束#########",JsonUtils.objectToJson(params) );
		}
		
	}

	@Override
	public String asynCallBack(@RequestParam Map<String, String> params) {
		// 1.日志记录
		log.info("#####支付宝异步通知synCallBack#####开始,params:{}", params);
		// 2.验签操作
		try {
			boolean signVerified = AlipaySignature.rsaCheckV1(params,public_key,charset,sign_type); // 调用SDK验证签名
			log.info("#####支付宝异步通知signVerified:{}######", signVerified);
			// ——请在这里编写您的程序（以下代码仅作参考）——
			if (!signVerified) {
				return Constants.PAY_FAIL;
			}
			// 商户订单号
			String outTradeNo = params.get("out_trade_no");
			
			TbPayExample example=new TbPayExample();
			Criteria criteria=example.createCriteria();
			criteria.andOrderidEqualTo(outTradeNo);
			List<TbPay> list=payMapper.selectByExample(example);
			if (list == null||list.size()==0) {
				return Constants.PAY_FAIL;
			}

			// 支付宝重试机制
			// 由于支付宝回调隔一段时间才回调,不是并行回调,可以用查询记录(日志)来防止重复修改订单状态,或增加积分
			// 消息重复消费问题,和支付宝类似,消息失败重发也不是并行执行的,是隔一段时间才重发的,可以使用全局ID+查询记录来解决
			// 如果是并行执行的话,同一时刻支付宝会发多次请求来回调的话,多个线程会并发同时执行下面代码,这个时候就需要使用锁来解决,最简单粗暴方式,使用数据库行锁记录锁 select .... for update来解决,效率低不推荐
			// 如果paymentInfoDao.updatePay发生延迟,也会可能导致并行情況,集群环境下可以使用分布式锁,单机环境下使用sychonsize关键字,保证同一时刻只能有一个线程来执行,这段代码若是没走完,会一直被锁着
			TbPay pay=list.get(0);
			Integer state = pay.getState();
			if (state == 1) {
				return Constants.PAY_SUCCESS;
			}

			// 支付宝交易号
			String tradeNo = params.get("trade_no");
			// 付款金额
			// String totalAmount = params.get("total_amount");
			// 判断实际付款金额与商品金额是否一致,不一致返回异常订单,钱原路退回
			// 修改 支付表状态
			pay.setState(1);// 标识为已经支付
			pay.setPlatformorderid(tradeNo);//第三方支付id,支付宝返回的交易号码
			// 手动 begin 开启事务
			Integer updateResult = payMapper.updateByPrimaryKeySelective(pay);
			if (updateResult <= 0) {
				return Constants.PAY_FAIL;
			}
			// 调用订单接口通知 支付状态
			String result=orderServiceFeign.update(154289514816926L, pay.getId()+"","1");
			TaotaoResult taotao=JsonUtils.jsonToPojo(result, TaotaoResult.class);
			if (taotao.getStatus()!=200) {
				// 回滚 手动回滚 rollback
				return Constants.PAY_FAIL;
			} 
			//手动提交 commit
			return Constants.PAY_SUCCESS;
		} catch (Exception e) {
			log.error("####支付宝异步通知出现异常,ERROR:", e);
			// 回滚 手动回滚 rollback
			return Constants.PAY_FAIL;
		} finally {
			log.info("#####支付宝异步通知synCallBack#####结束,params:{}", params);
		}
	}

}
